package com.jnshu.tools.binding;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

/**
 * @author Martin
 * @date 2019/8/9 21:19
 */
@Slf4j
public class RedisUtil {
    //redis缓存连接地址
    private static final String IP = "127.0.0.1";
    //redis密码
    private static final String PASSWORD = "123456";
    //端口
    private static final int PORT = 6379;
    //可用连接实例的最大数目，默认值为8；
    private static int MAX_TOTAL = 200;
    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
    private static int MAX_IDLE = 30;
    //等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。
    private static int MAX_WAIT = 1000;
    //连接超时时间（毫秒）
    private static int TIMEOUT = 6000;
    //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的
    private static boolean TEST_ON_BORROW = true;

    private static JedisPool jedisPool;

    /**
     * 初始化Redis连接池
     */
    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxIdle(MAX_IDLE);
            config.setMaxTotal(MAX_TOTAL);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, IP, PORT, TIMEOUT, PASSWORD);
        } catch (Exception e) {
            log.info("redis初始化失败：" + e.toString());
        }
    }

    /**
     * 获取Jedis实例
     *
     * @return Jedis
     */
    public synchronized static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                Jedis resource = jedisPool.getResource();
                return resource;
            } else {
                log.error("未获取到redis的资源信息");
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放jedis资源
     *
     * @param jedis
     */
    public static void returnBrokenResource(Jedis jedis) {
        if (null != jedis) {
            //注意这里不是关闭连接，在JedisPool模式下，Jedis会被归还给资源池。
            jedis.close();
        }
    }

    /*================================普通缓存方法========================================*/

    /**
     * 指定key值缓存失效时间
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public static boolean cacheExpire(String key, int time) {
        Jedis jedis = RedisUtil.getJedis();
        if (time > 0) {
            try {
                jedis.expire(key, time);
                return true;
            } catch (Exception e) {
                log.info("指定key失效时间失败");
                return false;
            }
        } else {
            log.info("时间time小于0");
            return false;
        }
    }

    /**
     * 普通缓存设置
     *
     * @param key
     * @param value
     * @return
     */
    public static boolean setObject(String key, Object value) {
        log.info("redis setObject方法key值为：" + key + "对象为：" + value);
        Jedis jedis = RedisUtil.getJedis();
        try {
            jedis.set(key, JSON.toJSONString(value));
            return true;
        } catch (Exception e) {
            log.info("redis setObject方法错误：" + exceptionWrite(e));
            return false;
        } finally {
            //释放redis连接到连接池
            RedisUtil.returnBrokenResource(jedis);
        }
    }

    /**
     * 普通缓存获去
     *
     * @param key
     * @return
     */
    public static Object getObject(String key) {
        log.info("redis getObject方法key值为：" + key);
        Jedis jedis = RedisUtil.getJedis();
        try {
            return JSON.parse(jedis.get(key));
        } catch (Exception e) {
            log.info("redis getObject方法错误：" + exceptionWrite(e));
            return exceptionWrite(e);
        }
    }

    /**
     * 慎用
     * flushDB清除当前DB 所有KEY
     * flushAll清除所有数据库的KEY
     *
     * @return boolean
     */
    public static boolean flushData() {
        log.info("redis flushData方法清除所有key");
        Jedis jedis = RedisUtil.getJedis();
        try {
            jedis.flushDB();
            return true;
        } catch (Exception e) {
            log.error("redis flushData方法执行错误：" + exceptionWrite(e));
            return false;
        }
    }

    /**
     * 判断是否拥有键值
     *
     * @param key
     * @return boolean
     */
    public static boolean hasKey(String key) {
        log.info("redis hasKey方法判断是否存在key：" + key);
        Jedis jedis = RedisUtil.getJedis();
        try {
            return jedis.exists(key);
        } catch (Exception e) {
            return false;
        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
    }

    /**
     * 删除key单个缓存
     *
     * @param key
     * @return
     */
    public static boolean delKey(String key) {
        log.info("redis delKey方法删除的key：" + key);
        Jedis jedis = RedisUtil.getJedis();
        try {
            jedis.del(key);
            return true;
        } catch (Exception e) {
            log.error("redis delKey方法执行错误：" + exceptionWrite(e));
            return false;
        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
    }

    /**
     * 存储list数据的缓存
     *
     * @param key
     * @param list
     * @return
     */
    public static boolean setList(String key, List<Object> list) {
        log.info("redis setList方法存储的key值为：" + key);
        Jedis jedis = RedisUtil.getJedis();
        try {
            jedis.set(key, JSON.toJSONString(list));
            return true;
        } catch (Exception e) {
            log.error("redis setList方法执行错误：" + exceptionWrite(e));
            return false;
        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
    }

    /**
     * 获取list数据的缓存
     *
     * @param key
     * @param value
     * @return
     */
    public static List getList(String key, Class value) {
        log.info("redis getList方法获取的key值为：" + key);
        Jedis jedis = RedisUtil.getJedis();
        try {
            return JSON.parseArray(jedis.get(key));
        } catch (Exception e) {
            log.error("redis getList方法执行错误：" + exceptionWrite(e));
            return null;
        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
    }

    /**
     * 返回异常栈信息，String类型.
     *
     * @param e Exception
     * @return boolean
     */
    private static String exceptionWrite(Exception e) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter printWriter = new PrintWriter(stringWriter);
        e.printStackTrace(printWriter);
        printWriter.flush();
        return stringWriter.toString();
    }

    /*================================搜索记录========================================*/
    /*
     * @Author bd
     * @Description
     * @Date 19:28 2019/8/12
     * @Param
     * @return
     **/

    /**
     * 通过key向list头部添加字符串
     *
     * @param key
     * @param strs 可以使一个string 也可以使string数组
     * @return 返回list的value个数
     */
    public static Long lpush(String key, String strs) {
        log.info("redis lpush方法存储的key值为：" + key);
        Jedis jedis = RedisUtil.getJedis();
        Long res = null;
        try {
            res = jedis.lpush(key, strs);

        } catch (Exception e) {
            log.error("redis lpush方法执行错误：" + e.getMessage());

        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
        return res;
    }

    /**
     * <p>
     * 通过key获取list指定下标位置的value
     * 如果start 为 0 end 为 -1 则返回全部的list中的value
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static List<String> lrange(String key, long start, long end) {
        log.info("redis lrange方法存储的key值为：" + key);
        Jedis jedis = RedisUtil.getJedis();
        List<String> res = null;
        try {
            res = jedis.lrange(key, start, end);
// 仅保留指定区间内的记录数，删除区间外的记录。下标从 0 开始，即 end 需要最大值 -1
            jedis.ltrim(key, 0, 10);
        } catch (Exception e) {
            log.error("redis lrange方法执行错误：" + e.getMessage());

        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
        return res;
    }

    /**
     * <p>
     * 删除指定的key,也可以传入一个包含key的数组
     * @param key 一个key 也可以使 string 数组
     * @return 返回删除成功的个数
     */

    public static Long del(String key) {
        log.info("redis del方法存储的key值为：" + key);
        Jedis jedis = RedisUtil.getJedis();
        Long res = null;
        try {
            res = jedis.del(key);
        } catch (Exception e) {
            log.error("redis del方法执行错误：" + e.getMessage());

        } finally {
            log.info("释放redis连接到连接池");
            RedisUtil.returnBrokenResource(jedis);
        }
        return res;
    }
}
